<script setup>
import {ElMessage, ElLoading} from 'element-plus'
import {VueDraggableNext} from 'vue-draggable-next'
import {reactive, onMounted, watch, ref} from 'vue'
import {deleteFile} from '@/api/file.js'
import {beforeUpload, uploadError} from '@/utils/index.js'
import {Delete} from '@element-plus/icons-vue'

defineOptions({
  name: 'ImageShow'
})

onMounted(() => {
  initBannerList()
  watch(() => props.list, () => {
    initBannerList()
  })
})

const initBannerList = () => {
  data.banner_list = props.list.map(file_id => {
    return {
      file_id: file_id,
      is_hover: false,
      url: imageSuffix + file_id
    }
  })
}

const uploadFiles = ref([])
const emit = defineEmits(['update:list'])
const imageSuffix = import.meta.env.VITE_IMAGE_SUFFIX
const data = reactive({
  banner_list: [], // 拖拽插件不建议直接改变父组件的传值，所以另建一个新数组
  file_list: [], //保存开启拖拽之前排序的数组
  drag_open: false //拖拽开启开关
})

const handleUploadError = () => {
  uploadFiles.value = []
  props.onError()
}

const successAction = (response) => {
  ElLoading.service({fullscreen: true}).close()
  if (response.code !== 200) {
    ElMessage.error(response.message)
    return
  }
  const d = response.data
  data.banner_list.push({
    file_id: d.file_id,
    is_hover: false,
    url: imageSuffix + d.file_id
  })
  emit('update:list', data.banner_list.map(item => item.file_id))
  uploadFiles.value = []
  props.onSuccess(d.file_id, props.params)
}

/**
 * 删除图片
 * @param {Number} i
 * @returns {Promise<void>}
 */
const deleteImage = async (i) => {
  const img = data.banner_list.splice(i, 1)[0]
  emit('update:list', data.banner_list.map(item => item.file_id))
  props.onDelete(img)
  await deleteFile(img.file_id)
}

/**
 * 开启拖拽
 */
const openDrag = () => {
  data.file_list = JSON.parse(JSON.stringify(data.banner_list)) //数组深拷贝
  data.drag_open = true
}

// 取消拖拽
const cancel = () => {
  data.banner_list = data.file_list
  data.drag_open = false
}
// 拖拽保存
const save = () => {
  data.drag_open = false
  emit('update:list', data.banner_list.map(item => item.file_id))
}

const props = defineProps({
  list: Array,
  limit: {
    type: Number,
    default: 1
  },
  multiple: {
    type: Boolean,
    default: false
  },
  action: {
    type: Function,
    default: () => {
      return import.meta.env.VITE_BASE_API + '/upload/image'
    }
  },
  uploadBefore: {
    type: Function,
    default: beforeUpload
  },
  customerExceed: {
    type: Function,
    default: () => {
    }
  },
  onError: {
    type: Function,
    default: uploadError
  },
  onSuccess: {
    type: Function,
    default: () => {
    }
  },
  onDelete: {
    type: Function,
    default: () => {
    }
  },
  showDrag: {
    type: Boolean,
    default: true
  },
  title: {
    type: String,
    default: ''
  },
  params: {
    type: Object,
    default: () => {
      return {}
    }
  },
  imageSize: {
    type: String,
    default: '148px'
  }
})

watch(() => props.list, (newValue) => {
  if (newValue.length > props.limit && props.limit !== 0) {
    ElMessage.warning(`当前最多可上传${props.limit}张图片`)
    return false
  }
  data.banner_list = newValue.map(file_id => {
    return {
      file_id: file_id,
      is_hover: false,
      url: imageSuffix + file_id
    }
  })
})
</script>
<template>
  <div class="com-image-drag">
    <div class="button-list" v-if="showDrag">
      <el-button
          @click="openDrag"
          v-if="!data.drag_open"
          :disabled="data.banner_list.length <= 1"
          type="text"
          size="small"
          class="operation-success"
      >拖拽排序
      </el-button>
      <el-button
          @click="save"
          v-if="data.drag_open"
          type="text"
          size="small"
          class="operation-success"
      >确认排序
      </el-button>
      <el-button
          @click="cancel"
          v-if="data.drag_open"
          type="text"
          size="small"
          class="operation-error"
      >取消排序
      </el-button>
    </div>
    <div class="image-list">
      <!-- 拖拽层 -->
      <div class="list-wrap" v-show="data.drag_open">
        <vue-draggable-next
            v-model="data.banner_list"
            :options="{
              animation: 150,
              ghostClass: 'sortable-ghost',
              chosenClass: 'chosenClass',
              scroll: true,
              scrollSensitivity: 200
            }"
        >
          <transition-group>
            <div
                class="image-item"
                :class="limit > 1 ? 'margin' : ''"
                v-for="($item, $index) in data.banner_list"
                :key="$index"
                :style="{ backgroundImage: `url(${$item.url})` }"
            />
          </transition-group>
        </vue-draggable-next>
      </div>
      <!-- 展示层 -->
      <div class="list-wrap" v-show="!data.drag_open">
        <div
            class="image-item"
            :class="limit > 1 ? 'margin' : ''"
            v-for="($item, $index) in data.banner_list"
            :key="$index"
            :style="{ backgroundImage: `url(${$item.url})`}"
            @mouseover.prevent="$item.is_hover = true"
            @mouseleave.prevent="$item.is_hover = false"
        >
          <div class="label" v-show="!$item.is_hover">
            <el-icon class="icon-success">
              <component is="Check"></component>
            </el-icon>
          </div>
          <div class="mask" v-show="$item.is_hover" @click="deleteImage($index)">
            <el-icon class="bin">
              <Delete/>
            </el-icon>
            <i class="el-icon-delete bin" @click="deleteImage($index)"></i>
          </div>
        </div>
        <el-upload
            v-show="limit === 0 || data.banner_list.length < limit"
            list-type="picture-card"
            name="file"
            class="upload-machine"
            :limit="limit"
            :disabled="data.drag_open"
            :action="action()"
            :on-error="handleUploadError"
            :file-list="uploadFiles"
            :on-success="successAction"
            :before-upload="uploadBefore"
            :show-file-list="false"
            :on-exceed="customerExceed"
            :multiple="multiple"
            enctype="multipart/form-data"
            accept="image/jpeg,image/png"
        >
          <span v-if="title !== ''" v-html="title"></span>
        </el-upload>
      </div>
    </div>
  </div>
</template>
<style>
.el-upload.el-upload--picture-card {
  background: transparent;
}

.upload-machine .el-upload.el-upload--picture-card {
  width: v-bind(imageSize);
  height: v-bind(imageSize);
}
</style>
<style lang="sass" scoped>
.com-image-drag
  &:after
    display: block
    clear: both
    content: ""

  .image-list
    float: left

    &:after
      display: block
      clear: both
      content: ""

    .list-wrap
      float: left
      position: relative

    .image-item
      width: v-bind(imageSize)
      height: v-bind(imageSize)
      position: relative
      border: 1px solid #c0ccda
      background-size: contain
      background-repeat: no-repeat
      background-position: 50% 50%
      border-radius: 6px
      float: left
      margin-right: 10px
      overflow: hidden
      cursor: pointer

      &.margin
        margin-right: 10px
        margin-bottom: 10px

      .label
        width: 46px
        height: 26px
        background-color: #13ce66
        color: #FFFFFF
        transform: rotate(45deg)
        text-align: center
        position: absolute
        right: -17px
        top: -7px

        .icon-success
          transform: rotate(-45deg)
          font-size: 24px
          margin-left: 4px
          margin-top: 4px

      .mask
        width: 100%
        height: 100%
        border-radius: 6px
        background-color: rgba(0, 0, 0, 0.5)
        position: relative
        display: flex
        align-items: center
        justify-content: center

        .bin
          color: #FFFFFF
          font-size: 20px

  .upload-machine
    float: left
    position: relative
    z-index: 1
    width: v-bind(imageSize)
    height: v-bind(imageSize)

    span
      font-size: 12px
      display: block
      width: 100%
      line-height: 20px
      position: absolute
      bottom: 0
      left: 0
      color: #999999
      padding: 0 5px

    &:after
      content: '+'
      display: block
      width: v-bind(imageSize)
      height: v-bind(imageSize)
      position: absolute
      right: 0
      top: 0
      color: #59a5e9
      text-align: center
      line-height: calc(v-bind(imageSize) - 10px)
      font-size: 40px
      padding: 0
      background-color: var(--el-fill-color-lighter)
      z-index: -1
</style>
